﻿using Manon.Repository.Collections;
using Manon.Repository.Repository;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using MySqlConnector;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

namespace Manon.Repository
{
    /// <summary>
    /// 工作单元的默认实现.
    /// </summary>
    /// <typeparam name="TContext"></typeparam>
    public class UnitOfWork : IUnitOfWork
    {
        protected readonly ICommonDbContext _context;
        protected bool _disposed = false;


        public UnitOfWork(ICommonDbContext context)
        {
            _context = context ?? throw new ArgumentNullException(nameof(context));
        }

        public DbSet<TEntity> Set<TEntity>() where TEntity : class
        {
            return _context.Set<TEntity>();
        }

        public void SetEntry<TEntity>(TEntity entity, EntityState entityState) where TEntity : class
        {
            _context.SetEntry<TEntity>(entity, entityState);
        }

        public void SetEntry(object entity, EntityState entityState)
        {
            _context.SetEntry(entity, entityState);
        }

        /// <summary>
        /// 获取DbContext
        /// </summary>
        public ICommonDbContext DbContext => _context;

        /// <summary>
        /// 开始一个事务
        /// </summary>
        /// <returns></returns>
        public Task<IDbContextTransaction> BeginTransactionAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            return _context.Database.BeginTransactionAsync(cancellationToken);
        }




        /// <summary>
        /// 执行原生sql语句
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public async Task<int> ExecuteSqlCommandAsync(string sql, params object[] parameters)
        {
            return await _context.Database.ExecuteSqlRawAsync(sql, parameters);
        }



        /// <summary>
        /// 使用原生sql查询来获取指定数据
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="sql"></param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public async Task<IEnumerable<TEntity>> FromSqlAsync<TEntity>(string sql, params object[] parameters) where TEntity : class, new()
        {
            return await _context.Database.SqlQueryAsync<TEntity>(sql, parameters);
        }


        public async Task<PagedList<TEntity>> GetPagedListBySqlAsync<TEntity>(string Sql, BasePageInput Input, params object[] parameters) where TEntity : class, new()
        {
            object? obj = await _context.Database.SqlQueryScalarObjectAsync(EntityFrameworkCoreExtensions.GetTotalCountSql(Sql), parameters);

            long totalCount = 0;
            long.TryParse(obj?.ToString(), out totalCount);
            var items = await _context.Database.SqlQueryAsync<TEntity>(EntityFrameworkCoreExtensions.GetPagedSql(Sql, Input.PageIndex, Input.IndexFrom, Input.PageSize), parameters);

            var pagedList = new PagedList<TEntity>()
            {
                PageIndex = Input.PageIndex,
                PageSize = Input.PageSize,
                IndexFrom = Input.IndexFrom,
                TotalCount = totalCount,
                Items = items,
                TotalPages = (int)Math.Ceiling(totalCount / (double)Input.PageSize)
            };
            return pagedList;
        }
         
        /// <summary>
        /// DbContext提交修改（异步）
        /// </summary>
        /// <returns></returns>
        public async Task<int> SaveChangesAsync()
        { 
            return await _context.SaveChangesAsync();
        }


        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                { 
                    _context.Dispose();
                }
            }

            _disposed = true;
        }


    }
























    ///// <summary>
    ///// 工作单元的默认实现.
    ///// </summary>
    ///// <typeparam name="TContext"></typeparam>
    //public class UnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : DbContext, ICommonDbContext
    //{
    //    protected readonly TContext _context;
    //    protected bool _disposed = false;
    //    protected Dictionary<Type, object> _repositories; 

    //    public UnitOfWork(TContext context)
    //    {
    //        _context = context ?? throw new ArgumentNullException(nameof(context));
    //    }

    //    public DbSet<TEntity> Set<TEntity>() where TEntity : class
    //    {
    //        return _context.Set<TEntity>();
    //    }

    //    /// <summary>
    //    /// 获取DbContext
    //    /// </summary>
    //    public TContext DbContext => _context;
    //    /// <summary>
    //    /// 开始一个事务
    //    /// </summary>
    //    /// <returns></returns>
    //    public IDbContextTransaction BeginTransaction()
    //    {
    //        return _context.Database.BeginTransaction();
    //    }


    //    /// <summary>
    //    /// 开始一个事务
    //    /// </summary>
    //    /// <returns></returns>
    //    public Task<IDbContextTransaction> BeginTransactionAsync(CancellationToken cancellationToken = default(CancellationToken))
    //    {
    //        return _context.Database.BeginTransactionAsync(cancellationToken);
    //    }


    //    /// <summary>
    //    /// 获取指定仓储
    //    /// </summary>
    //    /// <typeparam name="TEntity"></typeparam>
    //    /// <param name="hasCustomRepository"></param>
    //    /// <returns></returns>
    //    public IRepository<TEntity, TId> GetRepository<TEntity, TId>(bool hasCustomRepository = false) where TEntity : class, IBaseEntity<TId>
    //    {
    //        //if (_repositories == null)
    //        //{
    //        //    _repositories = new Dictionary<Type, object>();
    //        //}

    //        //Type type = typeof(IRepository<TEntity, TId>);
    //        //if (!_repositories.TryGetValue(type, out object repo))
    //        //{
    //        //    IRepository<TEntity, TId> newRepo = new Repository<TEntity, TId>(_context);
    //        //    _repositories.Add(type, newRepo);
    //        //    return newRepo;
    //        //}
    //        //return (IRepository<TEntity, TId>)repo;
    //        return null;
    //    }

    //    /// <summary>
    //    /// 获取指定仓储
    //    /// </summary>
    //    /// <typeparam name="TEntity"></typeparam>
    //    /// <param name="hasCustomRepository"></param>
    //    /// <returns></returns>
    //    public IRepository<TEntity> GetRepository<TEntity>(bool hasCustomRepository = false) where TEntity : class, IBaseEntity
    //    {
    //        //if (_repositories == null)
    //        //{
    //        //    _repositories = new Dictionary<Type, object>();
    //        //}

    //        //Type type = typeof(IRepository<TEntity>);
    //        //if (!_repositories.TryGetValue(type, out object repo))
    //        //{
    //        //    IRepository<TEntity> newRepo = new Repository<TEntity>(_context);
    //        //    _repositories.Add(type, newRepo);
    //        //    return newRepo;
    //        //}
    //        //return (IRepository<TEntity>)repo;
    //        return null;
    //    }

    //    /// <summary>
    //    /// 执行原生sql语句
    //    /// </summary>
    //    /// <param name="sql">sql语句</param>
    //    /// <param name="parameters">参数</param>
    //    /// <returns></returns>
    //    public int ExecuteSqlCommand(string sql, params object[] parameters)
    //    {
    //        return _context.Database.ExecuteSqlRaw(sql, parameters);
    //    }

    //    /// <summary>
    //    /// 执行原生sql语句
    //    /// </summary>
    //    /// <param name="sql">sql语句</param>
    //    /// <param name="parameters">参数</param>
    //    /// <returns></returns>
    //    public async Task<int> ExecuteSqlCommandAsync(string sql, params object[] parameters)
    //    {
    //        return await _context.Database.ExecuteSqlRawAsync(sql, parameters);
    //    }

    //    /// <summary>
    //    /// 使用原生sql查询来获取指定数据
    //    /// </summary>
    //    /// <typeparam name="TEntity"></typeparam>
    //    /// <param name="sql"></param>
    //    /// <param name="parameters">参数</param>
    //    /// <returns></returns>
    //    public IEnumerable<TEntity> FromSql<TEntity>(string sql, params object[] parameters) where TEntity : class, new()
    //    {
    //        return _context.Database.SqlQuery<TEntity>(sql, parameters);
    //    }

    //    /// <summary>
    //    /// 使用原生sql查询来获取指定数据
    //    /// </summary>
    //    /// <typeparam name="TEntity"></typeparam>
    //    /// <param name="sql"></param>
    //    /// <param name="parameters">参数</param>
    //    /// <returns></returns>
    //    public async Task<IEnumerable<TEntity>> FromSqlAsync<TEntity>(string sql, params object[] parameters) where TEntity : class, new()
    //    {
    //        return await _context.Database.SqlQueryAsync<TEntity>(sql, parameters);
    //    }


    //    public PagedList<TEntity> GetPagedListBySql<TEntity>(string Sql, BasePageInput Input, params object[] parameters) where TEntity : class, new()
    //    {
    //        int TotalCount = (int)_context.Database.SqlQueryScalarObject(EntityFrameworkCoreExtensions.GetTotalCountSql(Sql), parameters);
    //        var items = _context.Database.SqlQuery<TEntity>(EntityFrameworkCoreExtensions.GetPagedSql(Sql, Input.PageIndex, Input.IndexFrom, Input.PageSize), parameters).ToList();

    //        var pagedList = new PagedList<TEntity>()
    //        {
    //            PageIndex = Input.PageIndex,
    //            PageSize = Input.PageSize,
    //            IndexFrom = Input.IndexFrom,
    //            TotalCount = TotalCount,
    //            Items = items,
    //            TotalPages = (int)Math.Ceiling(TotalCount / (double)Input.PageSize)
    //        };
    //        return pagedList;
    //    }

    //    public async Task<PagedList<TEntity>> GetPagedListBySqlAsync<TEntity>(string Sql, BasePageInput Input, params object[] parameters) where TEntity : class, new()
    //    {
    //        long TotalCount = (long)(await _context.Database.SqlQueryScalarObjectAsync(EntityFrameworkCoreExtensions.GetTotalCountSql(Sql), parameters));
    //        var items = await _context.Database.SqlQueryAsync<TEntity>(EntityFrameworkCoreExtensions.GetPagedSql(Sql, Input.PageIndex, Input.IndexFrom, Input.PageSize), parameters);

    //        var pagedList = new PagedList<TEntity>()
    //        {
    //            PageIndex = Input.PageIndex,
    //            PageSize = Input.PageSize,
    //            IndexFrom = Input.IndexFrom,
    //            TotalCount = TotalCount,
    //            Items = items,
    //            TotalPages = (int)Math.Ceiling(TotalCount / (double)Input.PageSize)
    //        };
    //        return pagedList;
    //    }


    //    /// <summary>
    //    /// DbContext提交修改
    //    /// </summary>
    //    /// <returns></returns>
    //    public int SaveChanges()
    //    { 
    //        return _context.SaveChanges();
    //    }

    //    /// <summary>
    //    /// DbContext提交修改（异步）
    //    /// </summary>
    //    /// <returns></returns>
    //    public async Task<int> SaveChangesAsync()
    //    {
    //        var aaa = _context.ChangeTracker.Entries();

    //        return await _context.SaveChangesAsync();
    //    }






    //    public void Dispose()
    //    {
    //        Dispose(true);

    //        GC.SuppressFinalize(this);
    //    }
    //    protected virtual void Dispose(bool disposing)
    //    {
    //        if (!_disposed)
    //        {
    //            if (disposing)
    //            {
    //                // clear repositories
    //                if (_repositories != null)
    //                {
    //                    _repositories.Clear();
    //                }

    //                // dispose the db context.
    //                _context.Dispose();
    //            }
    //        }

    //        _disposed = true;
    //    }


    //}
}
